#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <vector>

using namespace std;

sem_t s1;// 读者信号灯
sem_t s2;// 写者信号灯
class Sem
{
public:
    Sem(sem_t sem):_sem(sem)
    {
        sem_init(&_sem, 0, 1);// 初始化
    }
    void P()
    {
        sem_wait(&_sem);// P操作
    }
    void V()
    {
        sem_post(&_sem);// V操作
    }
    ~Sem()
    {
        sem_destroy(&_sem);// 清理
    }
private:
    sem_t _sem;
};

// 实例化信号灯
Sem sem1(s1);
Sem sem2(s2);

// 互斥锁 
// 读者的互斥锁
pthread_mutex_t rmtx = PTHREAD_MUTEX_INITIALIZER;
// 写者的互斥锁
pthread_mutex_t wmtx = PTHREAD_MUTEX_INITIALIZER;
// 共享资源
static int count = 15;

// 读者执行的函数
void *Reader(void *args)
{
    string name = (char*)args;// 获取线程名
    while(true)
    {
        sem1.P();// 申请信号灯
        pthread_mutex_lock(&rmtx);// 加锁
        if(count > 0)
        {
            cout << name << " 读数据, count: " << count-- << endl;
        }
        else 
        {
            pthread_mutex_unlock(&rmtx);// 解锁
            sem2.V();// 释放信号灯
            break;
        }
        pthread_mutex_unlock(&rmtx);// 解锁
        sem2.V();// 释放信号灯
        sleep(1);
    }
    pthread_exit((void*)0); // 线程终止
}
// 写者执行的函数
void *Writer(void *args)
{
    string name = (char*)args;// 获取线程名
    while(true)
    {
        sem2.P();// 申请信号灯
        pthread_mutex_lock(&wmtx);// 加锁
        if(count > 0)
        {
            cout << name << " 写数据, count: " << count-- << endl;
        }
        else 
        {
            pthread_mutex_unlock(&wmtx);// 解锁
            sem1.V();// 释放信号灯
            break;
        }
        pthread_mutex_unlock(&wmtx);// 解锁
        sem1.V();// 释放信号灯
    }
    pthread_exit((void*)0);// 线程终止
}
// 读者
void StartRead(vector<pthread_t> *tptr)
{
    for(int i=0; i<4; i++)
    {
        char* Readname = new char[64];
        snprintf(Readname, 64, "ReadThread-%d", i+1);
        pthread_t rtid;
        pthread_create(&rtid, nullptr, Reader, Readname);
        tptr->emplace_back(rtid);// 保存线程
    }
}
// 写者
void StartWrite(vector<pthread_t> *tptr)
{
    for(int i=0; i<4; i++)
    {
        char* Writename = new char[64];
        snprintf(Writename, 64, "WriteThread-%d", i+1);
        pthread_t wtid;
        pthread_create(&wtid, nullptr, Writer, Writename);
        tptr->emplace_back(wtid);// 保存线程
    }
}
// 将所有创建的线程进行等待，防止资源泄漏
void WaitAllthread(vector<pthread_t> threads)
{
    for(auto &thread:threads)
    {
        pthread_join(thread, nullptr);
    }
}

int main()
{
    vector<pthread_t> threads;// 保存创建的线程
    StartRead(&threads);// 读者线程
    StartWrite(&threads);// 写者线程
    WaitAllthread(threads);// 线程等待
    return 0;
}